#include "Subsystems/BlockBehaviors/SubsystemCactusBlockBehavior.h"
#include "GameSingleton.h"
#include "GameRandom.hpp"
#include "Subsystems/SubsystemTimeOfDay.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Subsystems/SubsystemGameInfo.h"
#include "Managers/BlocksManager.h"
#include "Log.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentHealth.h"

#include "Blocks/AirBlock.h"
#include "Blocks/CactusBlock.h"

namespace PocketSurvival
{
    SubsystemCactusBlockBehavior::SubsystemCactusBlockBehavior()
    {
        m_handleBlocks.push_back(CactusBlock::Index());
    }

    // 没有判断光照
    void SubsystemCactusBlockBehavior::onPoll(int32_t value, int32_t x, int32_t y, int32_t z)
    {
        if (m_gameInfo->environmentBehaviorMode == EnvironmentBehaviorMode::Static)
        {
            return;
        }
        int32_t cellValue = m_terrain->getCellValue(x, y + 1, z);
        if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.25f && Terrain::ExtractContents(cellValue) == AirBlock::Index() && Terrain::ExtractLight(cellValue) >= 12)
        {
            int32_t cellContents = m_terrain->getCellContents(x, y - 1, z);
            int32_t cellContents2 = m_terrain->getCellContents(x, y - 2, z);
            if (cellContents2 != CactusBlock::Index() || cellContents != CactusBlock::Index())
            {
                m_toUpdateLock.lock();
                m_toUpdate[Point3(x, y + 1, z)] = value;
                m_toUpdateLock.unlock();
            }
        }
    }

    void SubsystemCactusBlockBehavior::onNeighborBlockChanged(int32_t x, int32_t y, int32_t z, int32_t neighborX, int32_t neighborY, int32_t neighborZ)
    {
        int32_t cellContents = m_terrain->getCellContents(x, y - 1, z);
        if (cellContents != 7 && cellContents != CactusBlock::Index())
        {
            m_terrain->destroyCell(0, x, y, z, 0, false);
        }
    }

    void SubsystemCactusBlockBehavior::onCollide(const CellFace &cellFace, float velocity, ComponentBody *componentBody)
    {
        if (componentBody->componentCreature != nullptr)
        {
            const std::string cause = "被仙人掌刺入";
            float amount = 0.01f * MathUtils::Abs(velocity) * m_timeOfDay->getGameTimeDelta();
            componentBody->componentCreature->componentHealth->injure(amount, entt::null, false, cause);
        }
    }

    void SubsystemCactusBlockBehavior::update(float dt)
    {
        if (m_timeOfDay->periodicGameTimeEvent(100.0f, 0.0f) == true)
        {
            std::lock_guard<SpinLock> lk(m_toUpdateLock);
            for (const auto &pair : m_toUpdate)
            {
                m_terrain->changeOldCell(pair.first, AirBlock::Index(), pair.second);
            }
            m_toUpdate.clear();
        }
    }

    void SubsystemCactusBlockBehavior::load(const nlohmann::json &json)
    {
        m_timeOfDay = GameSingleton::singletonPtr->getSingleton<SubsystemTimeOfDay>();
        m_terrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();
        m_gameInfo = GameSingleton::singletonPtr->getSingleton<SubsystemGameInfo>();
    }

    static const std::string subsystemName = "CactusBlockBehavior";
    const std::string &SubsystemCactusBlockBehavior::getName() const
    {
        return subsystemName;
    }
    SubUpdateType SubsystemCactusBlockBehavior::getUpdateType()
    {
        return SubUpdateType::MultiThreadUpdate;
    }
}
